package org.ssm.demo.utils;

import com.jcraft.jsch.*;
import com.jcraft.jsch.ChannelSftp.LsEntry;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;

import java.io.File;
import java.io.FileOutputStream;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.*;


/****
 * SFTP工具类
 */
public class SFTPHelperUtil {

    /***
     * 日志
     */
    private static final Log log = LogFactory.getLog(SFTPHelperUtil.class);


    /***
     * 文件名称
     */
    public static final String FILE_NAME = "name";

    /***
     * 文件路径
     */
    public static final String FILE_PATH = "path";

    /***
     * 文件
     */
    public static final String FILE_SIZE = "size";


    /***
     * FTP服务器IP
     */
    private String serverIp;

    /***
     * FTP服务器用户名
     */
    private String user;

    /***
     * FTP服务器密码
     */
    private String password;

    /***
     * FTP服务器端口
     */
    private String port;

    /***
     * FTP服务器模式
     */
    private String mode;

    /***
     * 远程文件路径
     */
    private String remoteFilePath;


    /***
     * 本地文件路径
     */
    private String localFilePath;

    private String bussinessName;


    public String getServerIp() {
        return serverIp;
    }

    public void setServerIp(String serverIp) {
        this.serverIp = serverIp;
    }

    public String getUser() {
        return user;
    }

    public void setUser(String user) {
        this.user = user;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getPort() {
        return port;
    }

    public void setPort(String port) {
        this.port = port;
    }

    public String getMode() {
        return mode;
    }

    public void setMode(String mode) {
        this.mode = mode;
    }

    public String getRemoteFilePath() {
        return remoteFilePath;
    }

    public void setRemoteFilePath(String remoteFilePath) {
        this.remoteFilePath = remoteFilePath;
    }

    public String getLocalFilePath() {
        return localFilePath;
    }

    public void setLocalFilePath(String localFilePath) {
        this.localFilePath = localFilePath;
    }

    public String getBussinessName() {
        return bussinessName;
    }

    public void setBussinessName(String bussinessName) {
        this.bussinessName = bussinessName;
    }

    private Session sshSession = null;

    private ChannelSftp channelSftp = null;

    /**
     * 初始化，连接SFTP服务器
     */

//    public SFTPHelperUtil(JSONObject config) {
//        serverIp = config.getString("serverIp");
//        port = config.getString("port");
//        user = config.getString("userName");
//        password = config.getString("password");
//        mode = config.getString("passive");
//        remoteFilePath = config.getString("remotePath");
//        localFilePath = config.getString("localPath");
//        bussinessName = config.getString("name");
//    }

    /**
     * connectionServer * 连接SFTP服务器
     */
    public void connectionServer() {
        try {
            JSch jsch = new JSch();
            sshSession = jsch.getSession(user, serverIp, port == null ? 22 : Integer.parseInt(port));
            sshSession.setPassword(password);
            Properties sshConfig = new Properties();
            sshConfig.put("StrictHostKeyChecking", "no");
            sshSession.setConfig(sshConfig);
            sshSession.connect();
            Channel channel = sshSession.openChannel("sftp");
            if (channel != null) {
                channel.connect();
                log.info("[" + bussinessName + "]" + " login SFTP " + serverIp + ":" + port + " success!");
            } else {
                log.error( "channel connecting failed.");
            }
            channelSftp = (ChannelSftp) channel;
        } catch (Exception e) {
            log.error("[" + bussinessName + "]" + " login FTP" + serverIp + ":" + port, e);
        }
    }

    /******************getfilelist1-start******************/
    /**
     * 列出文件目录
     * @return
     */
    @SuppressWarnings("rawtypes")
    public Vector getfileList(String directory) {
        if (null == channelSftp) {
            log.info("列出文件目录 channelSftp是===========空");
        }
        log.info("列出文件目录 directory============"+directory);
        log.info("列出文件目录 sftp==="+channelSftp);

        try {
            return channelSftp.ls(remoteFilePath);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 判断目录是否存在
     * @param directory
     * @return
     */
    @SuppressWarnings("DefaultLocale")
    public boolean isDirExist(String directory) {
        boolean isDirExistFlag = false;
        try {
            SftpATTRS sftpATTRS = channelSftp.lstat(directory);
            isDirExistFlag = true;
            return sftpATTRS.isDir();
        } catch (Exception e) {
            if (e.getMessage().toLowerCase().equals("no such file")) {
                isDirExistFlag = false;
            }
        }
        return isDirExistFlag;
    }

    /**
     * 验证文件目录
     * @param obj
     * @param methodName
     * @return
     */
    public List<String> validFileList(Object obj, String methodName) {
        List<String> fileList = new ArrayList<String>();
        try {
            boolean isChange = isDirExist(remoteFilePath);
            if (!isChange) {
                log.error("[" + bussinessName + "]" + "SFTP服务器上不存在该路径：" + remoteFilePath + ",请核实后重新配置");
                return fileList;
            }
            log.info("[" + bussinessName + "]" + "url = " + remoteFilePath);
            Vector v = getfileList(remoteFilePath);
            log.info("///////////////////// v===="+v);
            Iterator it = v.iterator();
            Class<?> clazz = obj.getClass();
            Method method = clazz.getMethod(methodName, String.class);
            if (null != v && v.size() > 0) {
                while (it.hasNext()) {
                    LsEntry entry = (LsEntry) it.next();
                    log.info("遍历出来的文件名  entry=="+entry);
                    String filename = entry.getFilename();
                    String filesize = String.valueOf(entry.getAttrs().getSize());
                    log.info("遍历出来的文件名  filename=="+filename);
                    log.info("[" + bussinessName + "]" + "遍历文件[" + filename + "]");
                    boolean isvalid =  (Boolean)method.invoke(obj, filename);
                    if (isvalid) {
                        fileList.add(filename);
                    }
                }
            }

        } catch (Exception e) {
            log.error("[" + bussinessName + "]" + "获取ftp文件目录失败...", e);
        }
        return fileList;
    }
    /******************getfilelist1-end******************/

    /******************getfilelist2-start******************/
    /**
     * getFTPFileList 获得文件和目录列表 云主机
     */
    public ArrayList<Map<String, String>> getFTPFileList() {
        ArrayList<Map<String, String>> fileList = new ArrayList<Map<String, String>>();
        listRemoteAllFiles(fileList, remoteFilePath);
        log.info("云主机 -- 获取到的文件个数： " + fileList.size());
        ArrayList<Map<String, String>> fileListMap = filterFileData(fileList);
        log.info("云主机 -- 获取最新的文件个数： " + fileListMap.size());
        return fileListMap;
    }

    /**
     * listRemoteAllFiles 获取文件目录列表
     *
     * @param fileList
     *            文件列表
     * @param path
     *            文件路径
     */
    public void listRemoteAllFiles(List<Map<String, String>> fileList, String path) {
        try {
            boolean isChange = isDirExist(path);
            if (!isChange) {
                log.error("FTP服务器上不存在该路径：" + path + ",请核实后重新配置");
                return;
            }
            log.info("url = " + path);
            Vector v = getfileList(remoteFilePath);
            Iterator it = v.iterator();
            if (null != v && v.size() > 0) {
                while (it.hasNext()) {
                    LsEntry entry = (LsEntry) it.next();
                    log.info("遍历出来的文件名  entry=="+entry);
                    String filename = entry.getFilename();
//                    String filesize = String.valueOf(entry.getAttrs().getSize());
                    log.info("遍历出来的文件名  filename=="+filename);
                    String vailtype="true";
                    if (vailtype.equals("true")) {
                        if(filename.split("-").length>1){//判断性能文件名格式是否正确
//                            if (FileDateUtil.validateFileDate(filename)) {
//                                pushFile(fileList, entry, path);
//                            }
                        }
                    } else {
                        pushFile(fileList, entry, path);
                    }
                }
            }
        } catch (Exception e) {
            log.error("获取ftp文件目录失败...", e);
        }
    }

    /**
     * pushFile 装载文件目录
     *
     * @param fileList
     *            文件列表
     * @param entry
     *            文件
     * @param path
     *            文件路径
     */
    public void pushFile(List<Map<String, String>> fileList, LsEntry entry, String path) {
        if (entry.getAttrs().isDir() && !entry.getFilename().equals(".") && !entry.getFilename().equals("..")) {
            listRemoteAllFiles(fileList, path + File.separator + entry.getFilename());
        } else if (!entry.getFilename().equals(".") && !entry.getFilename().equals("..")) {
            Map<String, String> o = new HashMap<String, String>(2);
            o.put(FILE_NAME, entry.getFilename());
            o.put(FILE_PATH, path + entry.getFilename());
            o.put(FILE_SIZE, String.valueOf(entry.getAttrs().getSize()));
            fileList.add(o);
        }
    }

    /**
     * 云主机选择 时间最近的文件进行入库
     *
     * @param fileList
     * @return
     */
    public ArrayList<Map<String, String>> filterFileData(ArrayList<Map<String, String>> fileList) {
        try {
            if (fileList.size() > 1) {
                ArrayList<Map<String, String>> fileListSize = new ArrayList<Map<String, String>>();
                String path = fileList.get(0).get(FILE_PATH);
                String name = fileList.get(0).get(FILE_NAME);

                SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
                Date fileDate = df.parse(name.split("-")[0]);
                Long max = fileDate.getTime();
                int fileLength = fileList.size();
                for (int i = 1; i < fileLength; i++) {
                    String fileNamek = fileList.get(i).get(FILE_NAME);
                    Date fileDatek = df.parse(fileNamek.split("-")[0]);
                    Long diff = fileDatek.getTime();
                    if (diff > max) {
                        max = diff;
                        path = fileList.get(i).get(FILE_PATH);
                        name = fileList.get(i).get(FILE_NAME);
                    }
                }
                fileList.clear();

                Map<String, String> o = new HashMap<String, String>();
                o.put(FILE_NAME, name);
                o.put(FILE_PATH, path);

                fileListSize.add(o);
                return fileListSize;
            } else {
                return fileList;
            }

        } catch (Exception e) {
            return fileList;
        }
    }
    /******************getfilelist2-end******************/

    /******************delete-start******************/
    /**
     * 删除远程文件
     * @param fileName
     * @return
     */
    public boolean  deleteRemoteFile(String fileName) {
        if(fileName == null || fileName.trim().equals("")){
            log.info("invalid filename");
            return false;
        }
        try {
//            channelSftp.cd(this.remoteFilePath);
            channelSftp.rm(fileName);
            log.info("file " + fileName + " successfully deleted");
            return true;
        }  catch (SftpException e) {
            e.printStackTrace();
            log.info("failed to delete file " + fileName,e);
            return  false;
        }
    }

    /**
     * 删除本地文件
     * @param fileName
     * @return
     */
    public boolean deleteLocalFile(String fileName) {
        boolean hasDeleteFile = false;
        String absolutePath = localFilePath + fileName;
        try {
            File file = new File(absolutePath);
            if (file.exists()) {
                hasDeleteFile = file.delete();
            } else {
                log.info("本地的缓存" + absolutePath + "不存在");
            }
        } catch (Exception e) {
            log.error("本地文件删除异常", e);
        }
        log.info("本地文件删除" + fileName + (hasDeleteFile ? "成功" : "失败"));
        return hasDeleteFile;
    }
    /******************delete-end******************/

    /******************download-start******************/
    /**
     * 创建目录
     * @param path
     */
    public  void mkdirs(String path) {
        log.info("创建目录 path======"+path);
        File f = new File(path);
        String fs = f.getParent();
        log.info("创建目录 fs======"+fs);
        f = new File(fs);
        log.info("创建目录 f======"+f);
        if (!f.exists()) {
            f.mkdirs();
        }
    }

    /**
     * 文件下载
     * @param fileName
     * @return
     */
    public boolean download(String fileName) {
        try {
            log.info("文件下载 fileName================="+fileName +"  this.localFilePath============"+this.localFilePath);

            channelSftp.cd(this.remoteFilePath);
            File file = new File(this.localFilePath + File.separator + fileName);
            file.setWritable(true,false);
            log.info("传入本地目录 this.localFilePath + File.separator + fileName ======"+this.localFilePath + File.separator + fileName);
            mkdirs(this.localFilePath + File.separator + fileName);
            FileOutputStream fout = new FileOutputStream(file);
            channelSftp.get(fileName, fout);
            fout.flush();
            fout.close();
            log.info("下载-------file================="+file);
            return true;
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return false;
    }

    /**
     * downloadFile 下载文件
     *
     * @param sftpFileList
     *            文件列表
     * @return
     */
    public boolean downloadFile(List<Map<String, String>> sftpFileList) {
        boolean sign = false;
        int j = 0;
        log.info("远程下载路径：" + remoteFilePath);
        log.info("本地存储路径：" + localFilePath);
        for (int i = 0; i < sftpFileList.size(); i++) {
            Map<String, String> mp = sftpFileList.get(i);
            sign = download(mp.get(FILE_NAME));
            j = j + (sign ? 1 : 0);
        }
        log.info("共下载了" + j + "个文件");
        return sign;
    }
    /******************download-end******************/


    /**
     * 断开服务器
     */
    public void logoutService() {
        if (channelSftp != null && channelSftp.isConnected()) {
            channelSftp.disconnect();
        }
        if (sshSession != null && sshSession.isConnected()) {
            sshSession.disconnect();
        }
    }

}
